#include "cem/assembler.h"
#include "cem/electromagnetics_system.h"
#include "cem/material_database.h"
#include "cem/mesh_manager.h"
#include "cem/parameter_reader.h"
#include "cem/solver_manager.h"
#include "cem/boundary_condition.h"

#include <gtest/gtest.h>

#include <libmesh/libmesh.h>
#include <libmesh/linear_implicit_system.h>
#include <libmesh/numeric_vector.h>

#include <fstream>
#include <string>

using cem::Assembler;
using cem::ElectromagneticsSystem;
using cem::MaterialDatabase;
using cem::MeshManager;
using cem::ParameterReader;
using cem::SolverManager;

// 全局 LibMesh 初始化指针, 由 main 负责构造并赋值
static libMesh::LibMeshInit * g_libmesh_init = nullptr;

// 函数: build_minimal_system
// 作用: 构造一个最小化的 ElectromagneticsSystem, 使用空网格 prepare_for_use, 解析最少参数.
// 参数: out_sys - 输出的系统对象; out_mesh_mgr - 输出的网格管理器(保持网格/通信器生命周期)
// 返回: 无
static void build_minimal_system(ElectromagneticsSystem & out_sys, MeshManager & out_mesh_mgr)
{
    ASSERT_NE(g_libmesh_init, nullptr) << "LibMeshInit is not initialized";

    MeshManager mesh(g_libmesh_init->comm());
    mesh.prepare_empty_mesh();

    // 参数读取器: 提供最小频率数组, 以令 omega 初始化路径可达
    ParameterReader params;
    const std::string tmp_path = "./tmp_minimal_solver_config.json";
    const std::string json_text = R"JSON({
        "FREQUENCY": [{"value": 1.0}],
        "PHYSICAL_AREA": {"EPSL": [], "COND": [], "MU": []}
    })JSON";
    {
        std::ofstream ofs(tmp_path);
        ofs << json_text;
    }
    ASSERT_TRUE(params.load_from_file(tmp_path));

    cem::MaterialDatabase material_db;
    cem::BoundaryConditionManager bc_mgr; // 空集合

    out_sys.initialize(params, mesh, material_db, bc_mgr);

    // 将 mesh 管理器返回给调用者以维持 Mesh 生命周期
    out_mesh_mgr = std::move(mesh);
}

// 用例: SolverManager 在右端项为零时直接将解置零并返回, 不抛出异常
TEST(SolverManagerTest, zero_rhs_short_circuit_solution)
{
    // 构造系统
    ElectromagneticsSystem system;
    MeshManager mesh_mgr(g_libmesh_init->comm());
    mesh_mgr.prepare_empty_mesh();

    build_minimal_system(system, mesh_mgr);

    // 装配 (当前装配器会产生零右端项或很小的右端项; 这里显式清零)
    Assembler assembler;
    assembler.assemble(system);

    auto & lin = system.linear_system();
    ASSERT_TRUE(lin.rhs != nullptr);

    lin.rhs->zero();
    lin.rhs->close();

    // 执行求解
    SolverManager sm;
    ParameterReader dummy_param; // 无显式 tol/iters
    sm.configure_from_parameters(dummy_param);

    ASSERT_NO_THROW(sm.solve(system));

    // 解应为零
    ASSERT_TRUE(lin.solution.get() != nullptr);
    EXPECT_DOUBLE_EQ(lin.solution->l2_norm(), 0.0);
    EXPECT_DOUBLE_EQ(lin.solution->linfty_norm(), 0.0);
}

// 函数: main
// 作用: 初始化 LibMesh 与 GoogleTest 并运行所有用例
// 参数: argc/argv - 命令行参数
// 返回: 测试返回码
int main(int argc, char ** argv)
{
    ::testing::InitGoogleTest(&argc, argv);
    libMesh::LibMeshInit init(argc, argv);
    g_libmesh_init = &init;
    return RUN_ALL_TESTS();
}